#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../include/file_descriptor.h"
#include "../include/narray.h"
#include "../include/block.h"
#include "../include/vfs_errorcodes.h"


void createroot()
{

	root = (struct node*) malloc(sizeof(struct node));
	
	struct node* temp;
	root->right_sibling = NULL;
	root->left_child = NULL;
	root->dirname = "root";
	root->nodefile_descriptor= NULL;
	strcpy(root->fullpath,"/");
	
}
void insertleft(struct node* rootloc, char* path, struct file_descriptor* fd) //Inserts the path in left siblings of root
{
	//printf("\n insertleft called\n");	
	struct node* temp;
	struct node* ptr;
	char temppath[100];
	temp = (struct node*) malloc(sizeof(struct node));
	temp->right_sibling = NULL;
	temp->left_child = NULL;
	temp->dirname = path;
	temp->nodefile_descriptor= NULL;
	strcpy(temppath,rootloc->fullpath);
	//printf("\n Fullpath %s ",rootloc->fullpath);
	strcat(temppath,temp->dirname);
	strcat(temppath,"/");
	strcpy(temp->fullpath,temppath);
	//printf("\n Levelcount %d\n", levelcount);
	//printf("\n File descriptor value %s \n",(fd->file_name));
	if(levelcount==-1)
	{	
		temp->nodefile_descriptor=fd;
		//printf("\n File descriptor value %s \n",(fd->file_name));
		//printf("\n File descriptor value %s \n",temp->nodefile_descriptor->file_name);
		
	}
	
	//printf("\n Fullpath %s ",temp->fullpath);
	//printf("\n Creating node with dirname %s in parent %s",path,rootloc->dirname);
	//printf("\n Levelcount %d\n", levelcount);
	
	if(rootloc->left_child == NULL)
	{
		rootloc->left_child = temp;
		//printf("\n if loop insertloc  \n");
	}

	else
	{
		ptr = rootloc->left_child;
		while(ptr->right_sibling != NULL)
		{
			ptr = ptr->right_sibling;
		}
		ptr->right_sibling = temp;
	}

	}

void display(struct node* rootloc)
{
	struct node* ptr;
	ptr = rootloc->left_child;
	printf("\n Name: %s", rootloc->dirname);
	printf("\n Full path: %s", Findparentpath(rootloc->fullpath));
	if(rootloc != root)
	{
		//	printf("\n descriptors %d",rootloc->nodefile_descriptor->dir_descriptors);
		//	printf("\n descriptor address %ld\n",rootloc->nodefile_descriptor->descriptor_address);
	}
	while(ptr != NULL)
	{
				
		display(ptr);		
		ptr = ptr->right_sibling;
	}
	printf("\n");
}

struct node* search(struct node* rootloc, char* path)
{	//printf("\n search called\n");	
	struct node* temp;
	if(rootloc->left_child!=NULL)
		temp=rootloc->left_child;
	else 
		return rootloc;
	while(temp!=NULL)
		{ 	
			if((strcmp(temp->dirname,path))==0)
			{	//printf("\n %s found\n",path); 
				return temp;
				}
		  temp=temp->right_sibling;
		}
	if(temp==NULL)
		return rootloc;
		
}
char* Trimpath(char* path)
{	//printf("\n trimpath called\n"); 	
	int i=0;
	char* trimpath=(char*)malloc(20*sizeof(char));

	while(*(path)!='/')
	{	//printf("\n while loop trimpath");
		if(*(path)=='\0')
			break;
		trimpath[i]=*path;
		i++,path++;
	}
	trimpath[i]='\0';
	//printf("\n %s\n", trimpath); 	
	return trimpath;

}

char* reducePathlength(char* path)
{	//printf("\n reducepath called\n");	
	while(*(path)!='/')
		{ path++;
		}	
	if(levelcount>0) 
		{	levelcount--; 
			//printf("%d reducepath\n",levelcount);
			return ++path;
		}
	else return NULL;
}
int countlevel(char* path)
{ 	//printf("\n countlevel called\n");
	int i=0;
	while(*path!='\0')
		{
			if(*path=='/')
			i++;
			path++;
		}
	return i;
}
void insert(struct node* rootloc, char* path, struct file_descriptor* fd)
{	//printf("\n insert called\n"); 	
	char* Partpath;
	char temppath[20];
	struct node* temp;
	//printf("\n%s\n",path);
	path=reducePathlength(path);
	//printf("\n Insertfunc %s \n",rootloc->dirname);
	//printf("\n%s\n",path);
	while(levelcount>=0)
	{	Partpath=Trimpath(path);
		//strcat(Partpath,"\0");
		//printf("\n%s\n",Partpath);
		temp=search(rootloc,Partpath);
		//printf("\n Insert while loop %s \n",temp->dirname);
		if(temp==rootloc)
			{ 	if(levelcount==0) 
					levelcount--;
				   	//printf("\nInsertleft being called levelcount%d\n",levelcount);
					insertleft(rootloc, Partpath,fd);}
		else {if(!strcmp(temp->dirname,path))
				{	//printf("Path already exists\n");
				 	levelcount--;
					if(levelcount==-1)//printf("\n Insert while loop %s \n",temp->fullpath);
					temp->nodefile_descriptor=fd;
					
				}
			     else
				insert(temp,path,fd);}
	}	
}

void narrayinsert(char* path,struct file_descriptor* fd)
{	
	char temppath[100];	
	strcpy(temppath,path);
	//printf("\n %s",fd->file_name);
	if(!strcmp(temppath,"/"))
		strcat(temppath,(fd->file_name));
	else
		{	strcat(temppath,"/");
			strcat(temppath,(fd->file_name));
		}
	//printf("\n %s",temppath);
	levelcount=countlevel(temppath);
	insert(root,temppath,fd);
}

struct node* Search_by_path(struct node* rootloc, char* path)
{   char* Partpath;
	struct node* temp,*temp2;
	//printf("\n %s \n", path);
	path=reducePathlength(path);
	//printf("\n %s \n", path);
	while(levelcount>=0)
	{	Partpath=Trimpath(path);
		//printf("\n %s \n", Partpath);
		temp=search(rootloc,Partpath);
		//printf("\n %s \n", temp->dirname);
		if(temp==rootloc)
			{ 	return NULL;
			}
		else
			{if(!strcmp(temp->dirname,path))
				{	//printf("Path already exists\n");
				 	levelcount--;
				 	return temp; 
				}
			     	else
					{   temp2=Search_by_path(temp,path);
						return temp2;
					}
			}
	}	

}

struct node* Searchnarray(char* path)
{ 
	//printf("\n Searrchnarray called");       
	levelcount=countlevel(path);
       if(!(strcmp(path,"/")))
       		return root;
	   return Search_by_path(root,path);
    
}

int deletenarray(char* path)
{
	struct node* temp, *temp2, *temp3;
	//printf("\n %s \n", path);
	if(!(strcmp(path,root->dirname)))
       		{	
       		//	printf("\n Can't delete root \n");
       			return 0;
       		}
	temp=Searchnarray(path);
	//printf("\n %s \n", temp->fullpath);
	if(temp!=NULL)
	{
			//printf("\n %s \n", Findparentpath(path));
			temp2=Searchnarray(Findparentpath(path));
			//printf("\n %s \n", temp2->fullpath);
			if((temp2->left_child)==temp)
				temp2->left_child=temp->right_sibling;
			else 
				{	temp3=temp2->left_child;
					while(temp3->right_sibling!=temp)
						temp3=temp3->right_sibling;
					temp3->right_sibling=temp->right_sibling;
;
				}


	}
	else
		{	//	printf("\n Node dosen't exists can't delete Exitting with return value 0 \n");
			return 0;
		}
}

char* Findparentpath(char* path)
{	//printf("\n Findparentpath called\n");	
	int pathlength=0;
	char* temppath=(char*)malloc(100*sizeof(char));
	strcpy(temppath,path);
	while(*(path)!='\0')
		{   
			pathlength++;
			path++;
		}	
	while(temppath[pathlength]!='/')
		{
			temppath[pathlength]='\0';
			pathlength--;
		}
	temppath[pathlength]='\0';
	if(!strcmp(temppath,""))
		strcpy(temppath,"/");
	return temppath;
		
}
void mountnarray(struct file_descriptor_list* FDList)
{
	//printf("Mountnarray() called");	
	struct file_descriptor_list* temp=FDList->next;
	if(temp!=NULL)
		while(temp!=NULL)
		{
			//printf("\n %u \n", &(temp->fdescriptor));			
			narrayinsert(temp->fpath,&(temp->fdescriptor));
			temp=temp->next;
		}
//	else 
//		printf("\n temp is null");
	
//	printf("Mountnarray() done");
//	display(root);
}

void displaystub(char* locpath, int flag, char* targetfilepath)
{
	struct node *temp;
	temp=Searchnarray(locpath);
	//printf("\n %s \n", temp->fullpath);
	//printf("\n flag %d \n",flag);
	FILE *list;
	list = fopen(targetfilepath,"w");
	if(list == NULL)
	{
		printf("%s%s\n", "listdir_FAILURE ", ERR_VFS_LISTDIR_04);
		return;
	}
	if(temp!=NULL)
		{
			if(flag==0)
				displaynonrecf(temp,list);				
				
			else
				displayf(temp,list);
		}
	else
//		printf("\n Path not existing \n");
	fclose(list);      //glibc
	printf("%s\n", "listdir_SUCCESS");

}

void displaynonrec(struct node* rootloc)
{
	struct node* ptr;
	ptr = rootloc->left_child;
	
	
	//printf("\n Displaynonrec console called");
		
	while(ptr != NULL)
	{
//		printf("\n Name: %s", ptr->dirname);
//		printf("\n Full Parent path: %s", Findparentpath(Findparentpath(ptr->fullpath)));		
		ptr = ptr->right_sibling;

	}
	//printf("\n Displaynonrec console exitting");
}

void displayf(struct node* rootloc,FILE* list)
{
	struct node* ptr;
	//printf("\n Display recursive called");
	ptr = rootloc->left_child;
	fprintf(list,"\n Name: %s", rootloc->dirname);
	fprintf(list,"\n Full Parent path: %s \n", Findparentpath(Findparentpath(rootloc->fullpath)));
	
	while(ptr != NULL)
	{
				
		displayf(ptr,list);		
		ptr = ptr->right_sibling;
	}
	//printf("\n");

}

void displaynonrecf(struct node* rootloc1, FILE* list)
{
	struct node* ptr;
	ptr = rootloc1->left_child;
	
	
	//printf("\n Displaynonrec file called");
	

	//displaynonrec(rootloc1);

	
	while(ptr != NULL)
	{		
		
		fprintf(list,"\n Name: %s", ptr->dirname);
		fprintf(list,"\n Full Parent path: %s \n", Findparentpath(Findparentpath(ptr->fullpath)));		
		//printf("\n displayed");
		
		ptr = ptr->right_sibling;
		

	}
	//printf("\n Displaynonrec file exitting");
}

struct node* Deleteinfo(struct node* rootloc, int *count, unsigned long int startblockaddress)
{	
//	printf("\n Deleteinfo called");	
	struct node *ptr, *temp;
	unsigned long int maximum;

	ptr = rootloc->left_child;
	temp=ptr;
	//printf("\n Count : %d \n", *count);
	//(*count)=(*count)+1;                 //consider this line and inside loop inequality
	maximum=ptr->nodefile_descriptor->descriptor_address;
	//printf("\n descriptor_address :%ld  \n",ptr->nodefile_descriptor->descriptor_address);
	//printf("\n  startblockaddress :%ld \n",startblockaddress);
	
		
	while(ptr != NULL)
	{
//	printf("\n  while descriptor_name : %s\n",ptr->nodefile_descriptor->file_name);
//	printf("\n  while descriptor_address : %ld\n",ptr->nodefile_descriptor->descriptor_address);
	if(ptr->nodefile_descriptor->descriptor_address>=startblockaddress && ptr->nodefile_descriptor->descriptor_address<(startblockaddress+BLOCK_SIZE))
		{
//			printf("\n  while descriptor_address : %ld\n",ptr->nodefile_descriptor->descriptor_address);			
			if(ptr->nodefile_descriptor->descriptor_address>=maximum)
				{
					maximum=ptr->nodefile_descriptor->descriptor_address;
					temp=ptr;
				}
			(*count)=(*count)+1;
			
		}
				
		ptr = ptr->right_sibling;

	}
	//printf("\n Count : %d \n", *count);	
	//printf("\n Deleteinfo exitting");
	return temp;

}

void repopulateFDlist(struct node* rootloc)
{
	struct node* ptr;
	struct file_descriptor temp;
	char temppath[120];
//	printf("\n repopulateFDlist called\n");
	ptr = rootloc->left_child;
	if(ptr==NULL)
		return;
	//printf("\n after ptr\n");
	temp=*(ptr->nodefile_descriptor);
	strcpy(temppath,Findparentpath(Findparentpath(ptr->fullpath)));

		
	if(!strcmp(temppath,""))
		strcpy(temppath,"/");
	
//	printf("\n Calling insertFD for Path %s \n",temppath);
//	printf("\n Calling insertFD for temp value : %s \n", temp.file_name);
	insertFD(temp,temppath);
	while(ptr != NULL)
	{	
		//printf("\n Ptr path %s", ptr->fullpath);
		
		repopulateFDlist(ptr);		
		ptr = ptr->right_sibling;
	}
	printf("\n");	
}
char* foldernamefrompath(char* path)
{	//printf("\n foldernamefrompath called\n");	
	int i=0,pathlength=0;
	char *foldername, *temppath;
	//printf("%s\n","check" );
	temppath=(char*)malloc(100*sizeof(char));
	foldername=(char*)malloc(20*sizeof(char));

	//char temppath[100];
	strcpy(temppath,path);
	while(*(path)!='\0')
	{ 
		pathlength++;
		path++;
	}	
	while(temppath[pathlength]!='/')
	pathlength--;
	pathlength++;
	while(temppath[pathlength]!='\0')
	{	foldername[i]=temppath[pathlength];
		i++;pathlength++;
	}

	foldername[i]='\0';
	//printf("\n foldername %s \n", foldername);
	free(temppath);
	return foldername;

}
void movenode(char* pathsource, char* pathdestination)
{
	struct node* temp,*temp2,*temp3,*temp4,*ptr;
	char temppath[100];
	//printf("\n Move node called\n");
	if(!strcmp(pathsource,"/"))
	{
//		printf("\n Can't move root exitting \n");
		return;
	}
	//printf("\n %s ", pathsource);
	temp=Searchnarray(pathsource);
	//printf("\n source fullpath %s \n ", temp->fullpath);
	temp2=Searchnarray(pathdestination);
	//printf("\n destination fullpath %s \n ", temp2->fullpath);
	if(temp==NULL)
	{
//		printf("\n Source dosen't exist\n");
		return ;
	}
	if(temp2==NULL)
	{
//		printf("\n Destination dosen't exist\n");
		return ;
	}	
	strcpy(temppath,pathdestination);
	strcat(temppath,"/");
	strcat(temppath,foldernamefrompath(pathsource));
	//printf("\n temppath for temp3 %s ", temppath);
	//exit(0);
	temp3=Searchnarray(temppath);
	//printf("\n %s \n ", temp3->fullpath);
	if(temp3!=NULL)
	{
//	printf("\n Destination Already have a folder of same name can't move \n");
	return;
	}
	//printf("\n pathsource2 %s ", pathsource);
	//printf("\n parent of pathsource %s ", Findparentpath(pathsource));
	if(!(strcmp(Findparentpath(pathsource),"")))
	{ 
		//printf("\n if Loop \n");
		//printf("\n %s ", pathsource);
		temp4=Searchnarray("/");
		//printf("\n %s ", temp4->fullpath);
	}

	else
		temp4=Searchnarray(Findparentpath(pathsource));
	//printf("\n %s ", temp4->fullpath);
	if(temp==(temp4->left_child))
	{	temp4->left_child=temp->right_sibling;
		//printf("\n %s ", temp4->left_child->fullpath);
	}
	else
	{	ptr=temp4->left_child;
		while(ptr->right_sibling!=temp)
		ptr=ptr->right_sibling;
		ptr->right_sibling=temp->right_sibling;
		//printf("\n %s ", ptr->right_sibling->fullpath);
	}
	if(temp2->left_child==NULL)
	{
		temp2->left_child=temp;
		temp->right_sibling=NULL;
	}
	else
	{
		ptr=temp2->left_child;
		while(ptr->right_sibling!=NULL)
		ptr=ptr->right_sibling;
		ptr->right_sibling=temp;
		temp->right_sibling=NULL;
	}
	temp=Searchnarray(pathdestination);
	temp2=temp->left_child;
	while(temp2->right_sibling!=NULL)
	temp2=temp2->right_sibling;
	//printf("\n temp2 path %s \n",temp2->fullpath);
	correctpath(temp2,temp);//to be called with temp2 as the node inserted and temp as its parent's location
}
void correctpath(struct node* rootloc, struct node* parent)
{
	struct node* ptr;
	ptr = rootloc->left_child;
	char temppath[100];
	char foldername[20];
	if(parent!=NULL)
	{
	//printf("\n Full path of parent folder: %s", parent->fullpath);
	strcpy(temppath,parent->fullpath);
	}
	//printf("\n Name: %s", rootloc->dirname);
	strcpy(foldername,foldernamefrompath(Findparentpath(rootloc->fullpath)));
	//printf("\n foldername %s", foldername);
	strcat(temppath,foldername);
	strcat(temppath,"/");
	//printf("\n new Possible path %s", temppath);
	strcpy(rootloc->fullpath,temppath);
	//printf("\n Full path: %s", rootloc->fullpath);

	while(ptr != NULL)
	{
	parent=rootloc;	
	correctpath(ptr, parent);	
	ptr = ptr->right_sibling;
	}
	//printf("\n");
}

void repopulateFDlist2(struct node* rootloc)
{
	struct node* ptr;
	struct file_descriptor temp;
	char temppath[120];
	//printf("\n repopulateFDlist2 called\n");
	ptr = rootloc->left_child;
	//printf("\n after ptr\n");
	//printf("\n %s \n",rootloc->fullpath);
	//printf("\n %s \n",ptr->fullpath);
	if(rootloc!=root)
			{
				//printf("\n inside if repopulateFDlist \n");
				temp=*(rootloc->nodefile_descriptor);
				strcpy(temppath,Findparentpath(Findparentpath(rootloc->fullpath)));
				if(!strcmp(temppath,""))
				strcpy(temppath,"/");
				//printf("\n Calling insertFD for Path %s \n",temppath);
				//printf("\n Calling insertFD for temp value : %s \n", temp.file_name);
				insertFD(temp,temppath);
			}
	
	while(ptr != NULL)
	{	
		//printf("\n Ptr path %s", ptr->fullpath);
		
		repopulateFDlist2(ptr);		
		ptr = ptr->right_sibling;
	}
//	printf("\n");
	
	
	
}




